<?php

namespace app\service;


use BaseComponents\base\ErrorCode;
use BaseComponents\base\Exception;

class WxService
{
    const APP_ID = 'wx1a286c785063ab55';

    const APP_SECRET = 'd608c90230238986cf4622f6ac85e106';

    public function getSignPackage()
    {
        $jsapiTicket = $this->getJsApiTicket();
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $timestamp = time();
        $nonceStr = $this->createNonceStr();

        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";

        $signature = sha1($string);

        $signPackage = array(
            "appId" => self::APP_ID,
            "nonceStr" => $nonceStr,
            "timestamp" => $timestamp,
            "url" => $url,
            "signature" => $signature,
            "rawString" => $string
        );
        return $signPackage;
    }

    private function createNonceStr($length = 16)
    {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * 获取ticket
     * @return bool|string
     * @throws Exception
     */
    private function getJsApiTicket()
    {
        /** @var \Redis $redis */
        $redis = \Yii::$app->get('redis');

        $key = 'wx:ticket';

        $ticket = $redis->get($key);

        if (!$ticket) {
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token={$this->getAccessToken()}";
            $json = json_decode($this->httpGet($url), true);

            if (isset($json['ticket']) && isset($json['expires_in'])) {
                $redis->set($key, $json['ticket'], $json['expires_in']);
                $ticket = $json['ticket'];
            } else {
                throw new Exception(ErrorCode::ERR_1005);
            }
        }

        return $ticket;
    }

    /**
     * 获取access token
     * @return bool|string
     * @throws Exception
     */
    public function getAccessToken()
    {
        /** @var \Redis $redis */
        $redis = \Yii::$app->get('redis');

        $key = 'wx:access_token';

        $accessToken = $redis->get($key);

        if (!$accessToken) {
            $result = $this->httpGet('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . self::APP_ID . '&secret=' . self::APP_SECRET);

            $json = json_decode($result, true);

            if (isset($json['expires_in']) && isset($json['access_token'])) {
                $redis->set($key, $json['access_token'], $json['expires_in']);
                $accessToken = $json['access_token'];
            } else {
                throw new Exception(ErrorCode::ERR_1004);
            }
        }

        return $accessToken;
    }

    private function httpGet($url)
    {
        $oCurl = curl_init();
        if (stripos($url, "https://") !== FALSE) {
            curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
            curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
        }
        curl_setopt($oCurl, CURLOPT_URL, $url);
        curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
        $sContent = curl_exec($oCurl);
        $aStatus = curl_getinfo($oCurl);
        curl_close($oCurl);
        if (intval($aStatus["http_code"]) == 200) {
            return $sContent;
        } else {
            return false;
        }
    }

}